﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using GameEngine;

namespace EngineTests2
{
    /// <summary>
    /// Class for generating moves in GameManager
    /// </summary>
    public static class MoveGen
    {
        /// <summary>
        /// Generates in GameManager the list of possible moves
        /// </summary>
        public static List<Move> GenerateMoves(GameManager mng, bool bLongestMoves = false)
        {
            List<Move> lstMoves = new List<Move>();

            // get figures that can move
            List<Position> lstStartPositions = mng.GetFiguresToMove();
            if(lstStartPositions.Count == 0)
                return lstMoves;


            // find figure moves
            foreach (Position startPos in lstStartPositions)
            {
                lstMoves.AddRange(FindMovesForFigure(mng, startPos));             
            }

            // if required to find the longest moves
            if (bLongestMoves == true)
                lstMoves = FindLongestMoves(lstMoves);

            return lstMoves;
        }

        /// <summary>
        /// Finds the longest moves
        /// </summary>
        private static List<Move> FindLongestMoves(List<Move> moves)
        {
            // calculate move lengths
            Dictionary<Move, int> map = new Dictionary<Move,int>();
            foreach (var m in moves)
                map[m] = CountMoveLength(m);          

            // get the longest move count
            int longest = map.Values.Max();

            // filter out the longest moves
            List<Move> lstLongestMoves = new List<Move>();
            foreach (var pair in map)
            {
                if (pair.Value == longest)
                    lstLongestMoves.Add(pair.Key);
            }

            return lstLongestMoves;
        }

        /// <summary>
        /// Counts move length
        /// </summary>
        private static int CountMoveLength(Move move)
        {
            Move moveStep = move;
            int count = 0;

            while (moveStep != null)
            {
                count++;
                moveStep = moveStep.nextMove;
            }

            return count;
        }

        /// <summary>
        /// Finds moves for a given figure
        /// </summary>
        private static List<Move> FindMovesForFigure(GameManager mng, Position figurePos, bool bMultipleJump = false, enumDiagonalDir? ignoredDir = null)
        {
            List<Move> lstMoves = new List<Move>();

            // returns figure moves
            List<Position> lstPos = new List<Position>();
            if (bMultipleJump == true && ignoredDir.HasValue)
            {
                List<Position> tmpList = new List<Position>();
                mng.GetFigureMultipleJumps(figurePos, tmpList);

                // filter out jumps in the ignored direction
                foreach (var pos in tmpList)
                {
                    if (figurePos.GetDiagonalDir(pos) != ignoredDir.Value)
                        lstPos.Add(pos);
                }
            }
            else
                mng.GetFigureMoves(figurePos, lstPos);

            foreach (Position lastPos in lstPos)
            {
                // complete and do move
                Move move = mng.CompleteMoveStep(figurePos, lastPos);
                mng.DoMoveStep(move);

                if (mng.DoesMoveContinue(move, lastPos) == false)
                {
                    // if move does not continues
                    lstMoves.Add(move);
                }
                else
                {
                    enumDiagonalDir ignoredDirection = move.endPos.GetDiagonalDir(move.startPos);
                    // the move continues
                    List<Move> followingMoveSteps = FindMovesForFigure(mng, lastPos, true, ignoredDirection);

                    // recopy the moves
                    foreach (Move followMove in followingMoveSteps)
                    {
                        Move prevMove = move.Copy();
                        prevMove.nextMove = followMove;

                        lstMoves.Add(prevMove);
                    }
                }

                mng.UndoMoveStep(move);
            }

            return lstMoves;
        }
    }
}
